package dk.dashboardFP.utils.keyListener {
	import flash.text.TextFieldType;
	import flash.text.TextField;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;

	/**
	 * @author josef
	 */
	public class KeyListener {

		private static var _oInstance : KeyListener;
		private static var _bCreatingInstance : Boolean = false;

		private var _doStage : Stage;
		private var _o_oDownKeys : Object = {};
		private var _o_oUpKeys : Object = {};
		private var _a_oDownKeys : Array = [];
		private var _currentEvent : KeyboardEvent;
		
		private var _keysNotFiltredWhenInTextField:Array=[17, 18, 16];

		public function KeyListener() {
			if( !_bCreatingInstance ) throw new Error("Singleton and can only be accessed through KeyListener.get_oInstance()");
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// setup
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function initKeyListener(doStage : Stage) : void {
			
			_doStage = doStage;
			
			//:::::::
			// register 
			_doStage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 0, true);
			_doStage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false, 0, true);
			
			_doStage.addEventListener(Event.DEACTIVATE, onDeactivateFP, false, 0, true);
		}

		private function onDeactivateFP(event : Event) : void {
			
			//:::::::
			// release all pressed keys 
			while (_a_oDownKeys.length != 0 && _o_oUpKeys[_a_oDownKeys[0]]) {
				KeyListenerKey(_o_oUpKeys[_a_oDownKeys[0]]).execute();
				_a_oDownKeys.splice(0, 1);
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// keys handling
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function addKeyDown(uintKeyCode : uint, fCallback : Function, bOnlyOneDispatch:Boolean=true) : void {
			
			if (!_oInstance) {
				throw new Error("KeyListener must be inited before adding keys");
			}
			
			if (!_o_oDownKeys[uintKeyCode]) {
				_o_oDownKeys[uintKeyCode] = new KeyListenerKey(uintKeyCode, bOnlyOneDispatch);
			}
			
			var oKLK : KeyListenerKey = _o_oDownKeys[uintKeyCode];
			oKLK.addCallBack(fCallback);
		}

		public function addKeyUp(uintKeyCode : uint, fCallback : Function) : void {

			if (!_oInstance) {
				throw new Error("KeyListener must be inited before adding keys");
			}
			
			if (!_o_oUpKeys[uintKeyCode]) {
				_o_oUpKeys[uintKeyCode] = new KeyListenerKey(uintKeyCode, false);
			}
			
			var oKLK : KeyListenerKey = _o_oUpKeys[uintKeyCode];
			oKLK.addCallBack(fCallback);
		}

		public function removeKeyUp(uintKeyCode : int, fCallback : Function) : void {
			if (_o_oUpKeys[uintKeyCode]) {
				KeyListenerKey(_o_oUpKeys[uintKeyCode]).removeCallback(fCallback);
			}
		}

		public function removeKeyDown(uintKeyCode : int, fCallback : Function=null) : void {
			if (_o_oDownKeys[uintKeyCode]) {
				KeyListenerKey(_o_oDownKeys[uintKeyCode]).removeCallback(fCallback);
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// key handlers
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function onKeyUp(event : KeyboardEvent) : void {
			
			if (_doStage.focus is TextField) {
				if (TextField(_doStage.focus).type==TextFieldType.INPUT) {
					if (_keysNotFiltredWhenInTextField.indexOf(event.keyCode)==-1) {
						return;
					}
				}
			}
			
			_currentEvent = event;
			
			if (_o_oUpKeys[event.keyCode]) {
				KeyListenerKey(_o_oUpKeys[event.keyCode]).execute();
			}
			
			if (_a_oDownKeys.indexOf(event.keyCode)!=-1) {
				_a_oDownKeys.splice(_a_oDownKeys.indexOf(event.keyCode), 1);
			}
		}

		private function onKeyDown(event : KeyboardEvent) : void {
			
			if (_doStage.focus is TextField) {
				if (TextField(_doStage.focus).type==TextFieldType.INPUT) {
					if (_keysNotFiltredWhenInTextField.indexOf(event.keyCode)==-1) {
						return;
					}
				}
			}
			
			_currentEvent = event;
			
			if (_o_oDownKeys[event.keyCode]) {
				if (KeyListenerKey(_o_oDownKeys[event.keyCode]).bOnlyDispatchOneDown) {
					if (_a_oDownKeys.indexOf(event.keyCode)==-1) {
						KeyListenerKey(_o_oDownKeys[event.keyCode]).execute();
					}
				} else {
					KeyListenerKey(_o_oDownKeys[event.keyCode]).execute();
				}
			}
			
			if (_a_oDownKeys.indexOf(event.keyCode)==-1) {
				_a_oDownKeys.push(event.keyCode);
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// singleton enforcer
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public static function getInstance() : KeyListener {
			if (!_oInstance) {
				_bCreatingInstance = true;
				_oInstance = new KeyListener();
				_bCreatingInstance = false;
			}
			return _oInstance;
		}
		
		public function get currentEvent() : KeyboardEvent {
			return _currentEvent;
		}
	}
}
